using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection.Emit;
using XenoGears.Functional;

namespace Truesight.Parser.Impl.Ops
{
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    internal static class OpCodeReference
    {
        private static Object _staticCtorLock = new Object();
        private static bool _staticCtorAintRun = true;

        private static HashSet<OpCode> _allOpCodes = new HashSet<OpCode>();

        static OpCodeReference()
        {
            if (_staticCtorAintRun)
            {
                // todo. get a grasp on memory models and analyze safety of this code
                // maybe we need a volatile modifier?!
                lock (_staticCtorLock)
                {
                    if (_staticCtorAintRun)
                    {
                        try
                        {
                            _allOpCodes.Add(OpCodes.Nop);
                            _allOpCodes.Add(OpCodes.Break);
                            _allOpCodes.Add(OpCodes.Ldarg_0);
                            _allOpCodes.Add(OpCodes.Ldarg_1);
                            _allOpCodes.Add(OpCodes.Ldarg_2);
                            _allOpCodes.Add(OpCodes.Ldarg_3);
                            _allOpCodes.Add(OpCodes.Ldloc_0);
                            _allOpCodes.Add(OpCodes.Ldloc_1);
                            _allOpCodes.Add(OpCodes.Ldloc_2);
                            _allOpCodes.Add(OpCodes.Ldloc_3);
                            _allOpCodes.Add(OpCodes.Stloc_0);
                            _allOpCodes.Add(OpCodes.Stloc_1);
                            _allOpCodes.Add(OpCodes.Stloc_2);
                            _allOpCodes.Add(OpCodes.Stloc_3);
                            _allOpCodes.Add(OpCodes.Ldarg_S);
                            _allOpCodes.Add(OpCodes.Ldarga_S);
                            _allOpCodes.Add(OpCodes.Starg_S);
                            _allOpCodes.Add(OpCodes.Ldloc_S);
                            _allOpCodes.Add(OpCodes.Ldloca_S);
                            _allOpCodes.Add(OpCodes.Stloc_S);
                            _allOpCodes.Add(OpCodes.Ldnull);
                            _allOpCodes.Add(OpCodes.Ldc_I4_M1);
                            _allOpCodes.Add(OpCodes.Ldc_I4_0);
                            _allOpCodes.Add(OpCodes.Ldc_I4_1);
                            _allOpCodes.Add(OpCodes.Ldc_I4_2);
                            _allOpCodes.Add(OpCodes.Ldc_I4_3);
                            _allOpCodes.Add(OpCodes.Ldc_I4_4);
                            _allOpCodes.Add(OpCodes.Ldc_I4_5);
                            _allOpCodes.Add(OpCodes.Ldc_I4_6);
                            _allOpCodes.Add(OpCodes.Ldc_I4_7);
                            _allOpCodes.Add(OpCodes.Ldc_I4_8);
                            _allOpCodes.Add(OpCodes.Ldc_I4_S);
                            _allOpCodes.Add(OpCodes.Ldc_I4);
                            _allOpCodes.Add(OpCodes.Ldc_I8);
                            _allOpCodes.Add(OpCodes.Ldc_R4);
                            _allOpCodes.Add(OpCodes.Ldc_R8);
                            _allOpCodes.Add(OpCodes.Dup);
                            _allOpCodes.Add(OpCodes.Pop);
                            _allOpCodes.Add(OpCodes.Jmp);
                            _allOpCodes.Add(OpCodes.Call);
                            _allOpCodes.Add(OpCodes.Calli);
                            _allOpCodes.Add(OpCodes.Ret);
                            _allOpCodes.Add(OpCodes.Br_S);
                            _allOpCodes.Add(OpCodes.Brfalse_S);
                            _allOpCodes.Add(OpCodes.Brtrue_S);
                            _allOpCodes.Add(OpCodes.Beq_S);
                            _allOpCodes.Add(OpCodes.Bge_S);
                            _allOpCodes.Add(OpCodes.Bgt_S);
                            _allOpCodes.Add(OpCodes.Ble_S);
                            _allOpCodes.Add(OpCodes.Blt_S);
                            _allOpCodes.Add(OpCodes.Bne_Un_S);
                            _allOpCodes.Add(OpCodes.Bge_Un_S);
                            _allOpCodes.Add(OpCodes.Bgt_Un_S);
                            _allOpCodes.Add(OpCodes.Ble_Un_S);
                            _allOpCodes.Add(OpCodes.Blt_Un_S);
                            _allOpCodes.Add(OpCodes.Br);
                            _allOpCodes.Add(OpCodes.Brfalse);
                            _allOpCodes.Add(OpCodes.Brtrue);
                            _allOpCodes.Add(OpCodes.Beq);
                            _allOpCodes.Add(OpCodes.Bge);
                            _allOpCodes.Add(OpCodes.Bgt);
                            _allOpCodes.Add(OpCodes.Ble);
                            _allOpCodes.Add(OpCodes.Blt);
                            _allOpCodes.Add(OpCodes.Bne_Un);
                            _allOpCodes.Add(OpCodes.Bge_Un);
                            _allOpCodes.Add(OpCodes.Bgt_Un);
                            _allOpCodes.Add(OpCodes.Ble_Un);
                            _allOpCodes.Add(OpCodes.Blt_Un);
                            _allOpCodes.Add(OpCodes.Switch);
                            _allOpCodes.Add(OpCodes.Ldind_I1);
                            _allOpCodes.Add(OpCodes.Ldind_U1);
                            _allOpCodes.Add(OpCodes.Ldind_I2);
                            _allOpCodes.Add(OpCodes.Ldind_U2);
                            _allOpCodes.Add(OpCodes.Ldind_I4);
                            _allOpCodes.Add(OpCodes.Ldind_U4);
                            _allOpCodes.Add(OpCodes.Ldind_I8);
                            _allOpCodes.Add(OpCodes.Ldind_I);
                            _allOpCodes.Add(OpCodes.Ldind_R4);
                            _allOpCodes.Add(OpCodes.Ldind_R8);
                            _allOpCodes.Add(OpCodes.Ldind_Ref);
                            _allOpCodes.Add(OpCodes.Stind_Ref);
                            _allOpCodes.Add(OpCodes.Stind_I1);
                            _allOpCodes.Add(OpCodes.Stind_I2);
                            _allOpCodes.Add(OpCodes.Stind_I4);
                            _allOpCodes.Add(OpCodes.Stind_I8);
                            _allOpCodes.Add(OpCodes.Stind_R4);
                            _allOpCodes.Add(OpCodes.Stind_R8);
                            _allOpCodes.Add(OpCodes.Add);
                            _allOpCodes.Add(OpCodes.Sub);
                            _allOpCodes.Add(OpCodes.Mul);
                            _allOpCodes.Add(OpCodes.Div);
                            _allOpCodes.Add(OpCodes.Div_Un);
                            _allOpCodes.Add(OpCodes.Rem);
                            _allOpCodes.Add(OpCodes.Rem_Un);
                            _allOpCodes.Add(OpCodes.And);
                            _allOpCodes.Add(OpCodes.Or);
                            _allOpCodes.Add(OpCodes.Xor);
                            _allOpCodes.Add(OpCodes.Shl);
                            _allOpCodes.Add(OpCodes.Shr);
                            _allOpCodes.Add(OpCodes.Shr_Un);
                            _allOpCodes.Add(OpCodes.Neg);
                            _allOpCodes.Add(OpCodes.Not);
                            _allOpCodes.Add(OpCodes.Conv_I1);
                            _allOpCodes.Add(OpCodes.Conv_I2);
                            _allOpCodes.Add(OpCodes.Conv_I4);
                            _allOpCodes.Add(OpCodes.Conv_I8);
                            _allOpCodes.Add(OpCodes.Conv_R4);
                            _allOpCodes.Add(OpCodes.Conv_R8);
                            _allOpCodes.Add(OpCodes.Conv_U4);
                            _allOpCodes.Add(OpCodes.Conv_U8);
                            _allOpCodes.Add(OpCodes.Callvirt);
                            _allOpCodes.Add(OpCodes.Cpobj);
                            _allOpCodes.Add(OpCodes.Ldobj);
                            _allOpCodes.Add(OpCodes.Ldstr);
                            _allOpCodes.Add(OpCodes.Newobj);
                            _allOpCodes.Add(OpCodes.Castclass);
                            _allOpCodes.Add(OpCodes.Isinst);
                            _allOpCodes.Add(OpCodes.Conv_R_Un);
                            _allOpCodes.Add(OpCodes.Unbox);
                            _allOpCodes.Add(OpCodes.Throw);
                            _allOpCodes.Add(OpCodes.Ldfld);
                            _allOpCodes.Add(OpCodes.Ldflda);
                            _allOpCodes.Add(OpCodes.Stfld);
                            _allOpCodes.Add(OpCodes.Ldsfld);
                            _allOpCodes.Add(OpCodes.Ldsflda);
                            _allOpCodes.Add(OpCodes.Stsfld);
                            _allOpCodes.Add(OpCodes.Stobj);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I1_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I2_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I4_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I8_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U1_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U2_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U4_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U8_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I_Un);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U_Un);
                            _allOpCodes.Add(OpCodes.Box);
                            _allOpCodes.Add(OpCodes.Newarr);
                            _allOpCodes.Add(OpCodes.Ldlen);
                            _allOpCodes.Add(OpCodes.Ldelema);
                            _allOpCodes.Add(OpCodes.Ldelem_I1);
                            _allOpCodes.Add(OpCodes.Ldelem_U1);
                            _allOpCodes.Add(OpCodes.Ldelem_I2);
                            _allOpCodes.Add(OpCodes.Ldelem_U2);
                            _allOpCodes.Add(OpCodes.Ldelem_I4);
                            _allOpCodes.Add(OpCodes.Ldelem_U4);
                            _allOpCodes.Add(OpCodes.Ldelem_I8);
                            _allOpCodes.Add(OpCodes.Ldelem_I);
                            _allOpCodes.Add(OpCodes.Ldelem_R4);
                            _allOpCodes.Add(OpCodes.Ldelem_R8);
                            _allOpCodes.Add(OpCodes.Ldelem_Ref);
                            _allOpCodes.Add(OpCodes.Stelem_I);
                            _allOpCodes.Add(OpCodes.Stelem_I1);
                            _allOpCodes.Add(OpCodes.Stelem_I2);
                            _allOpCodes.Add(OpCodes.Stelem_I4);
                            _allOpCodes.Add(OpCodes.Stelem_I8);
                            _allOpCodes.Add(OpCodes.Stelem_R4);
                            _allOpCodes.Add(OpCodes.Stelem_R8);
                            _allOpCodes.Add(OpCodes.Stelem_Ref);
                            _allOpCodes.Add(OpCodes.Ldelem);
                            _allOpCodes.Add(OpCodes.Stelem);
                            _allOpCodes.Add(OpCodes.Unbox_Any);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I1);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U1);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I2);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U2);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I4);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U4);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I8);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U8);
                            _allOpCodes.Add(OpCodes.Refanyval);
                            _allOpCodes.Add(OpCodes.Ckfinite);
                            _allOpCodes.Add(OpCodes.Mkrefany);
                            _allOpCodes.Add(OpCodes.Ldtoken);
                            _allOpCodes.Add(OpCodes.Conv_U2);
                            _allOpCodes.Add(OpCodes.Conv_U1);
                            _allOpCodes.Add(OpCodes.Conv_I);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_I);
                            _allOpCodes.Add(OpCodes.Conv_Ovf_U);
                            _allOpCodes.Add(OpCodes.Add_Ovf);
                            _allOpCodes.Add(OpCodes.Add_Ovf_Un);
                            _allOpCodes.Add(OpCodes.Mul_Ovf);
                            _allOpCodes.Add(OpCodes.Mul_Ovf_Un);
                            _allOpCodes.Add(OpCodes.Sub_Ovf);
                            _allOpCodes.Add(OpCodes.Sub_Ovf_Un);
                            _allOpCodes.Add(OpCodes.Endfinally);
                            _allOpCodes.Add(OpCodes.Leave);
                            _allOpCodes.Add(OpCodes.Leave_S);
                            _allOpCodes.Add(OpCodes.Stind_I);
                            _allOpCodes.Add(OpCodes.Conv_U);
                            _allOpCodes.Add(OpCodes.Arglist);
                            _allOpCodes.Add(OpCodes.Ceq);
                            _allOpCodes.Add(OpCodes.Cgt);
                            _allOpCodes.Add(OpCodes.Cgt_Un);
                            _allOpCodes.Add(OpCodes.Clt);
                            _allOpCodes.Add(OpCodes.Clt_Un);
                            _allOpCodes.Add(OpCodes.Ldftn);
                            _allOpCodes.Add(OpCodes.Ldvirtftn);
                            _allOpCodes.Add(OpCodes.Ldarg);
                            _allOpCodes.Add(OpCodes.Ldarga);
                            _allOpCodes.Add(OpCodes.Starg);
                            _allOpCodes.Add(OpCodes.Ldloc);
                            _allOpCodes.Add(OpCodes.Ldloca);
                            _allOpCodes.Add(OpCodes.Stloc);
                            _allOpCodes.Add(OpCodes.Localloc);
                            _allOpCodes.Add(OpCodes.Endfilter);
                            _allOpCodes.Add(OpCodes.Unaligned);
                            _allOpCodes.Add(OpCodes.Volatile);
                            _allOpCodes.Add(OpCodes.Tailcall);
                            _allOpCodes.Add(OpCodes.Initobj);
                            _allOpCodes.Add(OpCodes.Constrained);
                            _allOpCodes.Add(OpCodes.Cpblk);
                            _allOpCodes.Add(OpCodes.Initblk);
                            _allOpCodes.Add(OpCodes.Rethrow);
                            _allOpCodes.Add(OpCodes.Sizeof);
                            _allOpCodes.Add(OpCodes.Refanytype);
                            _allOpCodes.Add(OpCodes.Readonly);
                        }
                        finally 
                        {
                            _staticCtorAintRun = false;
                        }
                    }
                }
            }
        }

        public static ReadOnlyCollection<OpCode> AllOpCodes
        {
            get { return _allOpCodes.ToReadOnly(); }
        }
    }
}

